package dryven.codegen.asm;

import java.lang.reflect.Method;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import dryven.codegen.asm.typeinfo.ClassTypeInfo;
import dryven.codegen.asm.typeinfo.TypeInfo;

/**
 * Represents the top-most value on the operand stack
 * @author bwindels
 *
 */
public class TempValue extends AbstractInvokable implements Indexable {
	
	private TypeInfo _type;
	private MethodBuilder _mb;
	private boolean _popped;
	
	protected TempValue(TypeInfo type, MethodBuilder mb) {
		super(mb);
		_type = type;
		_mb = mb;
		_mb.pushCurrentStackValue(this);
	}
	
	public void checkValid() {
		checkValid(0);
	}
	
	public void checkValid(int position) {
		if(_popped) {
			throw new RuntimeException("Value got popped earlier (probably by some instruction, maybe you forgot to call duplicate?)");
		}
		if(!_mb.isCurrentValueOnStack(this,position)) {
			throw new RuntimeException("Value not on given position");
		}
	}

	@Override
	public TypeInfo getTypeInfo() {
		return _type;
	}
	
	public TempValue duplicate() {
		checkValid();
		getBuilder().getMethodVisitor().visitInsn(Opcodes.DUP);
		return new TempValue(_type, getBuilder());
	}


	@Override
	public ArrayEntry getArrayEntry(int index) {
		return new ArrayEntry(_type,this,index,getBuilder());
	}

	@Override
	public TempValue getArraySize() {
		getBuilder().getMethodVisitor().visitInsn(Opcodes.ARRAYLENGTH);
		pop();
		return new TempValue(new ClassTypeInfo(int.class),getBuilder());
	}

	public boolean isPopped() {
		return _popped;
	}

	protected void pop() {
		_popped = true;
		_mb.popCurrentStackValue(this);
	}

	@Override
	public FieldInstance getFieldInstance(FieldDefinition fd) {
		checkValid();
		return new FieldInstance(fd, getBuilder(),this);
	}

	@Override
	public void postOperation() {
		pop();
	}

	@Override
	public void preOperation(int pos) {
		checkValid(pos);
	}
}
